/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
/*
 * This copy of Woodstox XML processor is licensed under the
 * Apache (Software) License, version 2.0 ("the License").
 * See the License for details about distribution rights, and the
 * specific rights regarding derivate works.
 *
 * You may obtain a copy of the License at:
 *
 * http://www.apache.org/licenses/
 *
 * A copy is also included in the downloadable source code package
 * containing Woodstox, in file "ASL2.0", under the same directory
 * as this file.
 */
package com.je.bpm.core.converter.converter;

import com.je.bpm.core.converter.converter.child.config.*;
import com.je.bpm.core.converter.converter.child.config.form.TaskFormButtonConfigParser;
import com.je.bpm.core.converter.converter.child.config.form.TaskFormChildFuncConfigParser;
import com.je.bpm.core.converter.converter.child.config.form.TaskFormFieldConfigParser;
import com.je.bpm.core.converter.converter.child.config.form.TaskFormFieldSetValueConfigParser;
import com.je.bpm.core.converter.converter.export.ProccessCustomEventListenersConfigExport;
import com.je.bpm.core.converter.converter.util.BpmnXMLUtil;
import com.je.bpm.core.model.BaseElement;
import com.je.bpm.core.model.BpmnModel;
import com.je.bpm.core.model.ExtensionAttribute;
import com.je.bpm.core.model.button.Button;
import com.je.bpm.core.model.button.TaskButton;
import com.je.bpm.core.model.button.TaskCommitBreakdownButton;
import com.je.bpm.core.model.button.TaskDismissBreakdownButton;
import com.je.bpm.core.model.config.ButtonsConfig;
import com.je.bpm.core.model.config.CustomEvent;
import com.je.bpm.core.model.config.task.*;
import com.je.bpm.core.model.config.task.assignment.*;
import com.je.bpm.core.model.task.KaiteBaseUserTask;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.util.List;
import java.util.stream.Collectors;

import static org.apache.commons.lang3.StringUtils.join;

/**
 * 基础用户任务转换器
 */
public abstract class KaiteBaseUserTaskXmlConverter extends KaiteTaskXmlConverter {

    public KaiteBaseUserTaskXmlConverter() {
        super();
        //提交分解
        TaskCommitBreakdownButtonConfigParser taskCommitBreakdownButtonConfigParser = new TaskCommitBreakdownButtonConfigParser();
        //驳回配置
        TaskDismissConfigParser taskDismissConfigParser = new TaskDismissConfigParser();
        //预警与延期
        TaskEarlyWarningConfigParser taskEarlyWarningConfigParser = new TaskEarlyWarningConfigParser();
        //传阅
        TaskPassRoundConfigParser taskPassRoundConfigParser = new TaskPassRoundConfigParser();
        //按钮
        TaskButtonConfigParser taskButtonConfigParser = new TaskButtonConfigParser();
        //自定义事件
        TaskCustomEventListenersParser taskCustomEventListenersParser = new TaskCustomEventListenersParser();
        //加签
        TaskAddSignatureConfigParser taskAddSignatureConfigParser = new TaskAddSignatureConfigParser();
        //审批公告
        TaskApprovalNoticeConfigParser taskApprovalNoticeConfigParser = new TaskApprovalNoticeConfigParser();
        //表单控制配置赋值
        TaskFormFieldSetValueConfigParser taskFormFieldSetValueConfigParser = new TaskFormFieldSetValueConfigParser();
        //表单字段控制配置
        TaskFormFieldConfigParser taskFormFieldConfigParser = new TaskFormFieldConfigParser();
        //按钮控制
        TaskFormButtonConfigParser taskFormButtonConfigParser = new TaskFormButtonConfigParser();
        //子功能
        TaskFormChildFuncConfigParser taskFormChildFuncConfigParser = new TaskFormChildFuncConfigParser();

        childParserMap.put(taskCommitBreakdownButtonConfigParser.getElementName(), taskCommitBreakdownButtonConfigParser);
        childParserMap.put(taskDismissConfigParser.getElementName(), taskDismissConfigParser);
        childParserMap.put(taskEarlyWarningConfigParser.getElementName(), taskEarlyWarningConfigParser);
        childParserMap.put(taskPassRoundConfigParser.getElementName(), taskPassRoundConfigParser);
        childParserMap.put(taskButtonConfigParser.getElementName(), taskButtonConfigParser);
        childParserMap.put(taskCustomEventListenersParser.getElementName(), taskCustomEventListenersParser);
        childParserMap.put(taskAddSignatureConfigParser.getElementName(), taskAddSignatureConfigParser);
        childParserMap.put(taskApprovalNoticeConfigParser.getElementName(), taskApprovalNoticeConfigParser);
        childParserMap.put(taskFormFieldSetValueConfigParser.getElementName(), taskFormFieldSetValueConfigParser);
        childParserMap.put(taskFormFieldConfigParser.getElementName(), taskFormFieldConfigParser);
        childParserMap.put(taskFormButtonConfigParser.getElementName(), taskFormButtonConfigParser);
        childParserMap.put(taskFormChildFuncConfigParser.getElementName(), taskFormChildFuncConfigParser);


        defaultTaskAttributes.add(new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_DUEDATE));
        defaultTaskAttributes.add(new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_BUSINESS_CALENDAR_NAME));
        defaultTaskAttributes.add(new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_OWNER));
        defaultTaskAttributes.add(new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_PRIORITY));
    }

    @Override
    protected void writeAdditionalAttributes(BaseElement element, BpmnModel model, XMLStreamWriter xtw) throws Exception {
        //基础信息
        super.writeAdditionalAttributes(element, model, xtw);
        KaiteBaseUserTask userTask = (KaiteBaseUserTask) element;
        // write custom attributes
        BpmnXMLUtil.writeCustomAttributes(userTask.getAttributes().values(), xtw, defaultElementAttributes, defaultActivityAttributes, defaultTaskAttributes);
    }

    @Override
    protected void writeAdditionalChildElements(BaseElement element, BpmnModel model, XMLStreamWriter xtw) throws Exception {
        super.writeAdditionalChildElements(element, model, xtw);
        KaiteBaseUserTask kaiteUserTask = (KaiteBaseUserTask) element;
        //提交分解
        writeTaskCommitBreakdownConfig(kaiteUserTask.getCommitBreakdownButtonList(), xtw);
        //驳回配置
        writeDismissConfig(kaiteUserTask.getTaskDismissConfig(), xtw);
        //预警与延期
        writeTaskEarlyWarningAndPostponementConfig(kaiteUserTask.getTaskEarlyWarningAndPostponementConfig(), xtw);
        //传阅
        writePassRoundConfig(kaiteUserTask.getTaskPassRoundConfig(), xtw);
        //按钮
        writeTaskButtonConfig(kaiteUserTask.getButtons(), xtw);
        //自定义事件
        writeTaskCustomEventListenersConfig(kaiteUserTask.getCustomEventListeners(), xtw);
        //加签
        writeTaskAddSignatureConfig(kaiteUserTask.getAddSignatureConfig(), xtw);
        //审批公告
        writeTaskApprovalNoticeConfig(kaiteUserTask.getTaskApprovalNoticeConfig(), xtw);
        //表单控制配置
        writeFormBasicConfig(kaiteUserTask.getTaskFormBasicConfig(), xtw);
        //随机
        //writrTaskRandomConfig(kaiteUserTask.getTaskRandomConfig(), xtw);
    }

    protected void writrTaskRandomConfig(TaskRandomConfigImpl taskRandomConfig, XMLStreamWriter xtw) throws XMLStreamException {
        xtw.writeStartElement(BPMN2_PREFIX, PROPERTY_TASK_RANDOM_CONFIG, BPMN2_NAMESPACE);
        xtw.writeAttribute(PROPERTY_TASK_RANDOM_DISTRIBUTEDPOLLING, taskRandomConfig.isDistributedPolling() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_TASK_RANDOM_DISTRIBUTERANDOM, taskRandomConfig.isDistributeRandom() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_TASK_RANDOM_TEAM_NAME, ("".equals(taskRandomConfig.getTeamName()) || null == taskRandomConfig.getTeamName()) ? "" : taskRandomConfig.getTeamName());
        xtw.writeEndElement();
    }

    protected void writeTaskAssignmentConfig(TaskAssigneeConfigImpl taskAssigneeConfig, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_ASSIGNMENT_CONFIG, BPMN2_NAMESPACE);
        if (taskAssigneeConfig.getReferTo() == null) {
            xtw.writeAttribute(ELEMENT_ASSIGNMENT_REFERTO, "");
        } else {
            xtw.writeAttribute(ELEMENT_ASSIGNMENT_REFERTO, taskAssigneeConfig.getReferTo().toString());
        }
        List<BasicAssignmentConfigImpl> resources = taskAssigneeConfig.getResource();
        for (BasicAssignmentConfigImpl basicAssignmentConfig : resources) {
            xtw.writeStartElement(BPMN2_PREFIX, basicAssignmentConfig.getConfigType(), BPMN2_NAMESPACE);
            xtw.writeAttribute(ATTRIBUTE_TYPE, basicAssignmentConfig.getConfigType());
            xtw.writeAttribute(ELEMENT_ASSIGNMENT_RESOURCE_ENTRYPATH, basicAssignmentConfig.getEntryPath());
            writeAssignmentConfig(basicAssignmentConfig, xtw);
            xtw.writeEndElement();
        }
        xtw.writeEndElement();
    }

    /**
     * 提交分解
     *
     * @param list
     * @param xtw
     * @throws XMLStreamException
     */
    protected void writeTaskCommitBreakdownConfig(List<TaskCommitBreakdownButton> list, XMLStreamWriter xtw) throws XMLStreamException {
        xtw.writeStartElement(BPMN2_PREFIX, PROPERTY_TASK_COMMIT_BREAKDOWN_CONFIG, BPMN2_NAMESPACE);
        for (TaskCommitBreakdownButton taskCommitBreakdownButton : list) {
            xtw.writeStartElement(BPMN2_PREFIX, PROPERTY_TASK_COMMIT_BREAKDOWN_BUTTON, BPMN2_NAMESPACE);
            xtw.writeAttribute(PROPERTY_TASK_COMMIT_BREAKDOWN_BUTTON_NAME, taskCommitBreakdownButton.getName());
            xtw.writeAttribute(PROPERTY_TASK_COMMIT_BREAKDOWN_NODE_ID, taskCommitBreakdownButton.getNodeId());
            xtw.writeAttribute(PROPERTY_TASK_COMMIT_BREAKDOWN_NODE_NAME, taskCommitBreakdownButton.getNodeName());
            xtw.writeEndElement();
        }
        xtw.writeEndElement();
    }

    /**
     * 驳回分解
     *
     * @param list
     * @param xtw
     * @throws XMLStreamException
     */
    protected void writeTaskDismissBreakdownConfig(List<TaskDismissBreakdownButton> list, XMLStreamWriter xtw) throws XMLStreamException {
        xtw.writeStartElement(BPMN2_PREFIX, PROPERTY_TASK_COMMIT_BREAKDOWN_CONFIG, BPMN2_NAMESPACE);
        for (TaskDismissBreakdownButton taskCommitBreakdownButton : list) {
            xtw.writeStartElement(BPMN2_PREFIX, PROPERTY_TASK_COMMIT_BREAKDOWN_BUTTON, BPMN2_NAMESPACE);
            xtw.writeAttribute(PROPERTY_TASK_COMMIT_BREAKDOWN_BUTTON_NAME, taskCommitBreakdownButton.getName());
            xtw.writeAttribute(PROPERTY_TASK_COMMIT_BREAKDOWN_NODE_ID, taskCommitBreakdownButton.getNodeId());
            xtw.writeAttribute(PROPERTY_TASK_COMMIT_BREAKDOWN_NODE_NAME, taskCommitBreakdownButton.getNodeName());
            xtw.writeEndElement();
        }
        xtw.writeEndElement();
    }

    /**
     * 预警与延期
     *
     * @param earlyWarningAndPostponementConfig
     * @param xtw
     * @throws XMLStreamException
     */
    protected void writeTaskEarlyWarningAndPostponementConfig(TaskEarlyWarningAndPostponementConfigImpl earlyWarningAndPostponementConfig, XMLStreamWriter xtw) throws XMLStreamException {
        xtw.writeStartElement(BPMN2_PREFIX, PROPERTY_TASK_EARLYWARNINGANDPOSTPONEMENT_CONFIG, BPMN2_NAMESPACE);
        xtw.writeAttribute(ATTRIBUTEE_NABLE, earlyWarningAndPostponementConfig.isEnabled() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROCESSING_TIME_LIMIT_DURATION, earlyWarningAndPostponementConfig.getProcessingTimeLimitDuration());
        xtw.writeAttribute(PROCESSING_TIME_LIMIT_UNIT_NAME, earlyWarningAndPostponementConfig.getProcessingTimeLimitUnitName());
        xtw.writeAttribute(PROCESSING_TIME_LIMIT_UNIT_CODE, earlyWarningAndPostponementConfig.getProcessingTimeLimitUnitCode());
        xtw.writeAttribute(WARNING_TIME_LIMIT_DURATION, earlyWarningAndPostponementConfig.getWarningTimeLimitDuration());
        xtw.writeAttribute(WARNING_TIME_LIMIT_UNIT_NAME, earlyWarningAndPostponementConfig.getWarningTimeLimitUnitName());
        xtw.writeAttribute(WARNING_TIME_LIMIT_UNIT_CODE, earlyWarningAndPostponementConfig.getWarningTimeLimitUnitCode());
        xtw.writeAttribute(REMINDER_FREQUENCY_DURATION, earlyWarningAndPostponementConfig.getReminderFrequencyDuration());
        xtw.writeAttribute(REMINDER_FREQUENCY_UNIT_NAME, earlyWarningAndPostponementConfig.getReminderFrequencyUnitName());
        xtw.writeAttribute(REMINDER_FREQUENCY_UNIT_CODE, earlyWarningAndPostponementConfig.getReminderFrequencyUnitCode());
        List<EarlyWarningAndPostponementSource> list = earlyWarningAndPostponementConfig.getSource();
        for (EarlyWarningAndPostponementSource earlyWarningAndPostponementSource : list) {
            xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_RESOURCE, BPMN2_NAMESPACE);
            xtw.writeAttribute(ATTRIBUTE_TYPE, earlyWarningAndPostponementSource.getExecutionType().getValue());
            xtw.writeAttribute(PROPERTY_ASSIGNMENT_CUSTOM_SERVICENAME, earlyWarningAndPostponementSource.getService());
            xtw.writeAttribute(PROPERTY_ASSIGNMENT_CUSTOM_METHODNAME, earlyWarningAndPostponementSource.getMethod());
            xtw.writeEndElement();
        }
        xtw.writeEndElement();
    }

    /**
     * 自定义事件
     *
     * @param list
     * @param xtw
     * @throws XMLStreamException
     */
    protected void writeTaskCustomEventListenersConfig(List<CustomEvent> list, XMLStreamWriter xtw) throws XMLStreamException {
        xtw.writeStartElement(BPMN2_PREFIX, ATTRIBUTE_PROCESS_CUSTOM_EVENTLISTENERS_CONFIG, BPMN2_NAMESPACE);
        ProccessCustomEventListenersConfigExport.writeEvents(list, xtw, ATTRIBUTE_PROCESS_CUSTOM_TASK_EVENT_CODE);
        xtw.writeEndElement();
    }

    /**
     * 加签
     *
     * @param addSignatureConfig
     * @param xtw
     * @throws XMLStreamException
     */
    protected void writeTaskAddSignatureConfig(AddSignatureConfigImpl addSignatureConfig, XMLStreamWriter xtw) throws XMLStreamException {
        xtw.writeStartElement(BPMN2_PREFIX, PROPERTY_TASK_ADDSIGNATURE_CONFIG, BPMN2_NAMESPACE);
        xtw.writeAttribute(ATTRIBUTEE_NABLE, addSignatureConfig.getEnable() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_TASK_ADDSIGNATURE_UNLIMITED, addSignatureConfig.getUnlimited() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_TASK_ADDSIGNATURE_NOT_COUNTERSIGNED, addSignatureConfig.getNotCountersigned() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_TASK_ADDSIGNATURE_MANDATORY_COUNTERSIGNATURE, addSignatureConfig.getMandatoryCountersignature() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        writeCirculationRules(addSignatureConfig.getCirculationRules(), xtw);
        xtw.writeEndElement();
    }

    /**
     * 审批公告
     *
     * @param taskApprovalNoticeConfig
     * @param xtw
     * @throws XMLStreamException
     */
    protected void writeTaskApprovalNoticeConfig(TaskApprovalNoticeConfigImpl taskApprovalNoticeConfig, XMLStreamWriter xtw) throws XMLStreamException {
        xtw.writeStartElement(BPMN2_PREFIX, PROPERTY_TASK_APPROVALNOTICE_CONFIG, BPMN2_NAMESPACE);
        xtw.writeAttribute(PROPERTY_TASK_APPROVALNOTICE_PROCESSINITIATOR, taskApprovalNoticeConfig.isStartUser() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_TASK_APPROVALNOTICE_THISNODEAPPROVED, taskApprovalNoticeConfig.isApprovedPerson() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_TASK_APPROVALNOTICE_THISNODEAPPROVALDIRECTLYUNDERLEADER, taskApprovalNoticeConfig.isApproverDirectLeader() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_TASK_APPROVALNOTICE_THISNODEAPPROVALDEPTLEADER, taskApprovalNoticeConfig.isApproverDeptLeader() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeEndElement();
    }

    protected void writeFormEachFieldSetValueConfig(TaskFormFieldSetValueConfigImpl.FieldSetConfig fieldSetConfig, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_USERTASK_FORM_FIELDVALUE, BPMN2_NAMESPACE);
        writeQualifiedAttribute(ATTRIBUTE_CODE, fieldSetConfig.getCode(), xtw);
        writeQualifiedAttribute(ATTRIBUTE_NAME, fieldSetConfig.getName(), xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_FORM_FIELDVALUED, fieldSetConfig.getValue(), xtw);
        xtw.writeEndElement();
    }

    protected void writeFormEachFieldConfig(TaskFormFieldConfigImpl.FormFieldConfig formFieldConfig, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_USERTASK_FORM_FORMFIELD, BPMN2_NAMESPACE);
        writeQualifiedAttribute(ATTRIBUTE_CODE, formFieldConfig.getCode(), xtw);
        writeQualifiedAttribute(ATTRIBUTE_NAME, formFieldConfig.getName(), xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_FORM_FORMFIELD_EDITABLE, formFieldConfig.getEditable() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE, xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_FORM_FORMFIELD_READONLY, formFieldConfig.getReadonly() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE, xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_FORM_FORMFIELD_HIDDEN, formFieldConfig.getHidden() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE, xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_FORM_FORMFIELD_DISPLAY, formFieldConfig.getDisplay() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE, xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_FORM_FORMFIELD_REQUIRED, formFieldConfig.getRequired() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE, xtw);
        xtw.writeEndElement();
    }

    protected void writeFormEachChildFuncConfig(TaskFormChildFuncConfigImpl.ChildFuncConfig childFuncConfig, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_USERTASK_FORM_CHILDFUNC, BPMN2_NAMESPACE);
        writeQualifiedAttribute(ATTRIBUTE_CODE, childFuncConfig.getCode(), xtw);
        writeQualifiedAttribute(ATTRIBUTE_NAME, childFuncConfig.getName(), xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_FORM_CHILDFUNC_EDITABLE, childFuncConfig.getEditable() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE, xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_FORM_CHILDFUNC_HIDDEN, childFuncConfig.getHidden() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE, xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_FORM_CHILDFUNC_DISPLAY, childFuncConfig.getDisplay() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE, xtw);
        xtw.writeEndElement();
    }

    protected void writeFormEachButtonConfig(TaskFormButtonConfigImpl.ButtonConfig buttonConfig, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_USERTASK_FORM_BUTTON, BPMN2_NAMESPACE);
        writeQualifiedAttribute(ATTRIBUTE_CODE, buttonConfig.getCode(), xtw);
        writeQualifiedAttribute(ATTRIBUTE_NAME, buttonConfig.getName(), xtw);
        writeQualifiedAttribute(ATTRIBUTE_ENABLE, buttonConfig.getEnable() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE, xtw);
        xtw.writeEndElement();
    }

    private void writeCirculationRules(List<PassRoundResource> list, XMLStreamWriter xtw) throws XMLStreamException {
        for (PassRoundResource passRoundResource : list) {
            xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_USERTASK_PASSROUND_CIRCULATIONRULE, BPMN2_NAMESPACE);
            xtw.writeAttribute(ELEMENT_USERTASK_PASSROUND_RULE_TYPE, passRoundResource.getPassRoundTypeEnum().toString());
            xtw.writeAttribute(ELEMENT_USERTASK_PASSROUND_ID, passRoundResource.getResourceId());
            xtw.writeAttribute(ELEMENT_USERTASK_PASSROUND_NAME, passRoundResource.getResourceName());
            xtw.writeAttribute(ELEMENT_USERTASK_PASSROUND_SERVICE, passRoundResource.getService());
            xtw.writeAttribute(ELEMENT_USERTASK_PASSROUND_METHOD, passRoundResource.getMethod());
            xtw.writeEndElement();
        }
    }

    /**
     * 传阅
     *
     * @param taskPassRoundConfig
     * @param xtw
     * @throws Exception
     */
    protected void writePassRoundConfig(TaskPassRoundConfigImpl taskPassRoundConfig, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_USERTASK_PASSROUND_CONFIG, BPMN2_NAMESPACE);
        xtw.writeAttribute(ATTRIBUTE_ENABLE, taskPassRoundConfig.isEnable() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(ATTRIBUTE_USERTASK_PASSROUND_AUTO, taskPassRoundConfig.isAuto() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        writeCirculationRules(taskPassRoundConfig.getPassRoundResourceList(), xtw);
        xtw.writeEndElement();
    }

    protected void writeEachLabelCommentConfig(String key, String value, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_USERTASK_LABEL_COMMENT, BPMN2_NAMESPACE);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_COMMENT_LABEL, key, xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_COMMENT_CONTENT, value, xtw);
        xtw.writeEndElement();
    }

    /**
     * 驳回设置
     *
     * @param taskDismissConfig
     * @param xtw
     * @throws Exception
     */
    protected void writeDismissConfig(TaskDismissConfigImpl taskDismissConfig, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, PROPERTY_USERTASK_DISMISS_CONFIG, BPMN2_NAMESPACE);
        //可驳回
        xtw.writeAttribute(ATTRIBUTE_ENABLE, taskDismissConfig.isEnable() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        //可驳回节点id
        xtw.writeAttribute(PROPERTY_USERTASK_DISMISS_TASKID, taskDismissConfig.getDismissTaskId());
        //驳回后是否启用直送按钮
        xtw.writeAttribute(PROPERTY_USERTASK_DISMISS_ENABLEDIRECTSEND, taskDismissConfig.isDirectSendAfterDismiss() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        //被驳回后强制提交 只能提交，不能直送
        xtw.writeAttribute(PROPERTY_USERTASK_DISMISS_FORCECOMMITAFTERDISMISS, taskDismissConfig.isForceCommitAfterDismiss() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        //被驳回后禁用送交
        xtw.writeAttribute(PROPERTY_USERTASK_DISMISS_DISABLESENDAFTERDISMISS, taskDismissConfig.getDisableSendAfterDismiss() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        //不可退回
        xtw.writeAttribute(PROPERTY_USERTASK_DISMISS_NORETURN, taskDismissConfig.getNoReturn() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        //可直接提交退回人
        xtw.writeAttribute(PROPERTY_USERTASK_DISMISS_DIRECTSENDAFTERRETURN, taskDismissConfig.getDirectSendAfterReturn() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        //驳回分解
        writeTaskDismissBreakdownConfig(taskDismissConfig.getCommitBreakdown(), xtw);
        xtw.writeEndElement();
    }

    protected void writeDelegateConfig(TaskDelegateConfigImpl taskDelegateConfig, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_USERTASK_DELEGATE_CONFIG, BPMN2_NAMESPACE);
        writeQualifiedAttribute(ATTRIBUTE_ENABLE, taskDelegateConfig.isEnable() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE, xtw);
        xtw.writeEndElement();
    }

    protected void writeTaskDelayConfig(TaskDelayConfigImpl taskDelayConfig, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_USERTASK_DELAY_CONFIG, BPMN2_NAMESPACE);
        writeQualifiedAttribute(ATTRIBUTE_ENABLE, taskDelayConfig.isEnable() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE, xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_DELAY_TIMETYPE, taskDelayConfig.getDelayTimesType().name(), xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_DELAY_PERIOD, String.valueOf(taskDelayConfig.getPeriod()), xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_DELAY_TIMES, String.valueOf(taskDelayConfig.getDelayTimes()), xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_DELAY_CALLBACKSERVICENAME, taskDelayConfig.getCallbackServiceName(), xtw);
        xtw.writeEndElement();
    }

    protected void writeTaskEachCommentConfig(String key, String value, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_USERTASK_COMMENT, BPMN2_NAMESPACE);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_COMMENT_KEY, key, xtw);
        writeQualifiedAttribute(ATTRIBUTE_USERTASK_COMMENT_VALUE, value, xtw);
        xtw.writeEndElement();
    }

    /**
     * 按钮配置
     *
     * @param taskButtons
     * @param xtw
     * @throws Exception
     */
    protected void writeTaskButtonConfig(ButtonsConfig<TaskButton> taskButtons, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_BUTTONS_CONFIG, BPMN2_NAMESPACE);
        for (Button each : taskButtons.getButtons()) {
            writeEachTaskButtonConfig(each, xtw);
        }
        xtw.writeEndElement();
    }

    protected void writeEachTaskButtonConfig(Button taskButton, XMLStreamWriter xtw) throws Exception {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_TASK_BUTTON, BPMN2_NAMESPACE);
        xtw.writeAttribute(ATTRIBUTE_ID, taskButton.getId());
        xtw.writeAttribute(ATTRIBUTE_BUTTON_ID, taskButton.getId());
        xtw.writeAttribute(ATTRIBUTE_BUTTON_NAME, taskButton.getName());
        xtw.writeAttribute(ATTRIBUTE_BUTTON_CODE, taskButton.getCode());
        xtw.writeAttribute(ATTRIBUTE_BUTTON_OPERATION, taskButton.getOperationId());
        if (taskButton.getCustomizeComments() == null) {
            xtw.writeAttribute(ATTRIBUTE_BUTTON_CUSTOMIZE_COMMENTS, "");
        } else {
            xtw.writeAttribute(ATTRIBUTE_BUTTON_CUSTOMIZE_COMMENTS, taskButton.getCustomizeComments());
        }
        if (taskButton.getCustomizeName() == null) {
            xtw.writeAttribute(ATTRIBUTE_BUTTON_CUSTOMIZE_NAME, "");
        } else {
            xtw.writeAttribute(ATTRIBUTE_BUTTON_CUSTOMIZE_NAME, taskButton.getCustomizeName());
        }
        if (taskButton.getDisplayExpressionWhenStarted() == null) {
            xtw.writeAttribute(ATTRIBUTE_TASK_BUTTON_DISLAY_EXPRESSION, "");
        } else {
            xtw.writeAttribute(ATTRIBUTE_TASK_BUTTON_DISLAY_EXPRESSION, taskButton.getDisplayExpressionWhenStarted());
        }
        if (taskButton.getAppListeners() == null) {
            xtw.writeAttribute(ATTRIBUTE_BUTTON_APP_LISTENERS, "");
        } else {
            xtw.writeAttribute(ATTRIBUTE_BUTTON_APP_LISTENERS, taskButton.getAppListeners());
        }

        if (taskButton.getPcListeners() == null) {
            xtw.writeAttribute(ATTRIBUTE_BUTTON_PC_LISTENERS, "");
        } else {
            xtw.writeAttribute(ATTRIBUTE_BUTTON_PC_LISTENERS, taskButton.getPcListeners());
        }

        if (taskButton.getBackendListeners() == null) {
            xtw.writeAttribute(ATTRIBUTE_BUTTON_BACKEND_LISTENERS, "");
        } else {
            xtw.writeAttribute(ATTRIBUTE_BUTTON_BACKEND_LISTENERS, taskButton.getBackendListeners());
        }

        xtw.writeEndElement();
    }

    private void writeAssignmentResourceConfig(List<AssigneeResource> resources, XMLStreamWriter xtw) throws XMLStreamException {
        for (AssigneeResource assigneeResource : resources) {
            xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_ASSIGNMENT_RESOURCE_CONFIG, BPMN2_NAMESPACE);
            xtw.writeAttribute(ELEMENT_ASSIGNMENT_RESOURCE_NAME, assigneeResource.getName());
            xtw.writeAttribute(ELEMENT_ASSIGNMENT_RESOURCE_CODE, assigneeResource.getCode());
            xtw.writeAttribute(ELEMENT_ASSIGNMENT_RESOURCE_ID, assigneeResource.getId());
            xtw.writeEndElement();
        }
    }

    private void writeAssignmentPermissionConfig(AssignmentPermission permission, XMLStreamWriter xtw) throws XMLStreamException {
        xtw.writeStartElement(BPMN2_PREFIX, ELEMENT_ASSIGNMENT_RESOURCE_PERMISSION_CONFIG, BPMN2_NAMESPACE);
        xtw.writeAttribute(PROPERTY_ASSIGNMENT_PERMISSION_COMPANY, permission.getCompany() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_ASSIGNMENT_PERMISSION_COMPANY_SUPERVISION, permission.getCompanySupervision() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_ASSIGNMENT_PERMISSION_DEPT, permission.getDept() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_ASSIGNMENT_PERMISSION_DEPT_ALL, permission.getDeptAll() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_ASSIGNMENT_PERMISSION_DIRECT_LEADER, permission.getDirectLeader() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_ASSIGNMENT_PERMISSION_DEPT_LEADER, permission.getDeptLeader() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_ASSIGNMENT_PERMISSION_SUPERVISION_LEADER, permission.getSupervisionLeader() ? ATTRIBUTE_VALUE_TRUE : ATTRIBUTE_VALUE_FALSE);
        xtw.writeAttribute(PROPERTY_ASSIGNMENT_PERMISSION_SQL, permission.getSql());
        xtw.writeAttribute(PROPERTY_ASSIGNMENT_PERMISSION_SQL_REMARKS, permission.getSqlRemarks());
        xtw.writeEndElement();
    }

    protected void writeAssignmentConfig(BasicAssignmentConfigImpl assignmentConfig, XMLStreamWriter xtw) throws Exception {
        //角色、部门、岗位
        if (assignmentConfig instanceof PositionAssignmentConfigImpl || assignmentConfig instanceof DepartmentAssignmentConfigImpl ||
                assignmentConfig instanceof RoleAssignmentConfigImpl || assignmentConfig instanceof UserAssignmentConfigImpl ||
                assignmentConfig instanceof FormFieldAssignmentConfigImpl) {
            writeAssignmentResourceConfig(assignmentConfig.getResource(), xtw);
        }

        if (assignmentConfig instanceof PositionAssignmentConfigImpl || assignmentConfig instanceof DepartmentAssignmentConfigImpl ||
                assignmentConfig instanceof RoleAssignmentConfigImpl) {
            writeAssignmentPermissionConfig(assignmentConfig.getPermission(), xtw);
        }

        if (assignmentConfig instanceof OrgTreeAssignmentConfigImpl) {
            xtw.writeAttribute(ATTRIBUTEE_NABLE, "true");
        }

        if (assignmentConfig instanceof CustomAssignmentConfigImpl) {
            xtw.writeAttribute(PROPERTY_ASSIGNMENT_CUSTOM_SERVICENAME, ((CustomAssignmentConfigImpl) assignmentConfig).getServiceName());
            xtw.writeAttribute(PROPERTY_ASSIGNMENT_CUSTOM_METHODNAME, ((CustomAssignmentConfigImpl) assignmentConfig).getMethodName());
        }

        //特殊处理
        if (assignmentConfig instanceof SpecialAssignmentConfigImpl) {
            String str = join(((SpecialAssignmentConfigImpl) assignmentConfig).getSpecialType().stream().map(Enum::toString).collect(Collectors.toList()), ",");
            xtw.writeAttribute(ATTRIBUTE_SPECTIAL_TYPES, str);
        }

        //sql
        if (assignmentConfig instanceof BusinessSqlAssignmentConfigImpl) {
            xtw.writeAttribute(ATTRIBUTE_SQL, ((BusinessSqlAssignmentConfigImpl) assignmentConfig).getSql());
        }

        //人员矩阵
        if (assignmentConfig instanceof PersonnelMatrixConfigImpl) {
            PersonnelMatrixConfigImpl.Config config = ((PersonnelMatrixConfigImpl) assignmentConfig).getConfig();
            xtw.writeAttribute(MATRIX_NAME, config.getMatrixName());
            xtw.writeAttribute(MATRIX_ID, config.getMatrixId());
            xtw.writeAttribute(RESULT_FIELD, config.getResultField());
            xtw.writeAttribute(RESULT_FIELD_ID, config.getResultFieldId());
            List<PersonnelMatrixConfigImpl.Config.ConditionalInfo> list = config.getConditionalInfos();
            for (PersonnelMatrixConfigImpl.Config.ConditionalInfo conditionalInfo : list) {
                xtw.writeStartElement(BPMN2_PREFIX, CONDITIONAL_INFO, BPMN2_NAMESPACE);
                xtw.writeAttribute(CONDITION, conditionalInfo.getCondition());
                xtw.writeAttribute(CONDITION_VALUE, conditionalInfo.getConditionValue());
                xtw.writeAttribute(CONDITION_TYPE, conditionalInfo.getValueType());
                xtw.writeEndElement();
            }
        }
    }


}
